package cn.yangliu.nacos.comm.config.security.handler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.authentication.AuthenticationDetailsSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 认证相关接口
 *
 * <p>
 *
 * @author 杨柳
 */
@RestController
@Api(value = "认证控制", tags = "认证控制")
@ConditionalOnClass(Authentication.class)
@ConditionalOnProperty(prefix = "security.commom", name = "enable", havingValue = "true", matchIfMissing = true)
public class AuthenticateController {

    /**
     * current class instance's member.
     * The Authentication manager.
     */
    @Autowired
    private AuthenticationManager authenticationManager;
    /**
     * current class instance's member.
     * The Event publisher.
     */
    @Autowired
    protected ApplicationEventPublisher eventPublisher;
    /**
     * current class instance's member.
     * The Authentication success handler.
     */
    @Autowired
    private AuthenticationSuccessHandler authenticationSuccessHandler;
    /**
     * current class instance's member.
     * The Authentication failure handler.
     */
    @Autowired
    private AuthenticationFailureHandler authenticationFailureHandler;

    /**
     * current class instance's member.
     * The Authentication details source.
     */
    private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource =
            new WebAuthenticationDetailsSource();
    /**
     * current class instance's member.
     * The Session strategy.
     */
    private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy();

    /**
     * 登录认证
     *
     * @param request       the request
     * @param response      the response
     * @param userLoginInfo pack params
     * @throws Exception the exception
     */
    @PostMapping("/login")
    @ApiOperation(value = "登录", tags = "认证控制")
    public void auth(HttpServletRequest request, HttpServletResponse response,
					 @Validated UserLoginInfo userLoginInfo) throws Exception {

        String username = userLoginInfo.getUsername();
        String password = userLoginInfo.getPassword();

        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        try{
            //登录认证
            token = (UsernamePasswordAuthenticationToken) authenticationManager.authenticate(token);
        }catch (AuthenticationException e){
            authenticationFailureHandler.onAuthenticationFailure(request, response, e);
            return;
        }
        token.setDetails(authenticationDetailsSource.buildDetails(request));
        sessionStrategy.onAuthentication(token, request, response);
        SecurityContextHolder.getContext().setAuthentication(token);
        this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(token, this.getClass()));

        authenticationSuccessHandler.onAuthenticationSuccess(request, response, token);

    }

    /**
     * The interface User login info.
     *
     * @author 问道于盲
     */
    @Data
    private static class UserLoginInfo {

        /**
         * current class instance's member.
         * The Username.
         */
        private String username;

        /**
         * current class instance's member.
         * The Password.
         */
        private String password;
	}
}
